package com.so.studyonline.controller;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.so.studyonline.annotation.PassToken;
import com.so.studyonline.service.SoUserService;
import com.so.studyonline.service.TokenService;
import com.so.studyonline.utils.CreateJpgToVerify;
import com.so.studyonline.mapper.SoUserMapper;
import com.so.studyonline.model.SoUser;
import com.so.studyonline.utils.ResMessage;
import com.so.studyonline.mapper.SoUserMapper;
import com.so.studyonline.utils.CreateJpgToVerify;
import com.so.studyonline.utils.ResMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.imageio.ImageIO;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Controller
public class LoginController {

    private SoUserService soUserService;

    @Autowired
    public void setSoUserService(SoUserService soUserService) {
        this.soUserService = soUserService;
    }

    private TokenService tokenService;

    @Autowired
    public void setTokenService(TokenService tokenService) {
        this.tokenService = tokenService;
    }

    /**
     * 登录首页
     *
     * @return mav 首页视图
     */
    @RequestMapping("/")
    public ModelAndView indexPage() {
        // 加载视图
        ModelAndView mav = new ModelAndView();
        mav.addObject("content", "api");
        mav.setViewName("/index.html");
        return mav;
    }

    /**
     * @param request  请求信息
     * @param response 响应信息
     * @return 返回结果值
     * @apiNote 登录入口
     */
    @PassToken
    @RequestMapping("api/pub/submit")
    @ResponseBody
    public String main(HttpServletRequest request, HttpServletResponse response, @RequestBody JSONObject userLogin) {
        // 参数
        String userNo = userLogin.getString("userNo");
        String password = userLogin.getString("password");
        String verifyCode = userLogin.getString("verifyCode");
        // before search
        if (userNo.equals("") || password.equals("")) {
            return ResMessage.error("001002", "用户名或密码未输入！");
        }
        // 用户信息查询
        SoUser soUser = new SoUser();
        soUser.setUserNo(userNo);
        soUser.setPassword(password);
        SoUser userFind = soUserService.findByUserInfo(soUser);
        if (userFind == null) {
            // 未查询到用户
            return ResMessage.error("001", "用户不存在或密码错误");
        }
        if (userFind.getPassword().equals(soUser.getPassword())) {
            // 登录信息校验通过
            // 生成token
            String token = tokenService.getToken(userFind);
            if (token.equals("")) {
                // token 生成失败
                return ResMessage.error("002002", "token生成失败");
            }

            // 设置用户表token
            SoUser upUser = new SoUser();
            upUser.setToken(token);
            upUser.setUserNo(userFind.getUserNo());
            soUserService.updateOneUser(upUser);

            // 成功信息返回
            userFind.setToken(token);
            userFind.setPassword("");
            // 设置 cookie
            writeCookie(response, "token", token, 3600);
            return ResMessage.success(userFind);
        }

        // 密码错误
        return ResMessage.error("002001", "用户密码错误");
    }

    /**
     * @param request  请求信息
     * @param response 响应信息
     * @apiNote 获取图片验证码
     */
    @PassToken
    @RequestMapping("api/pub/getVerifyCode")
    @ResponseBody
    public void getVerifyCode(HttpServletRequest request, HttpServletResponse response) {
        CreateJpgToVerify createJpgToVerify = new CreateJpgToVerify();
        String roundNum = String.valueOf(System.currentTimeMillis());
        BufferedImage image = createJpgToVerify.createImg(request, roundNum);

        response.setContentType("image/jpeg");
        ImageIO.setUseCache(false);
        try {
            ImageIO.write(image, "jpg", response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * cookie 写入
     *
     * @param response   响应
     * @param cookieName 名称
     * @param value      值
     */
    public void writeCookie(HttpServletResponse response, String cookieName, String value, int maxAge) {
        Cookie cookie = new Cookie(cookieName, value);
        cookie.setPath("/");
        cookie.setMaxAge(maxAge);
        response.addCookie(cookie);
    }

    /**
     * 退出
     *
     * @return 结果
     */
    @PassToken
    @RequestMapping("api/logout")
    @ResponseBody
    public String logout(HttpServletResponse response) {
        writeCookie(response, "token", null, 0);
        return ResMessage.success();
    }

    /**
     * 根据 token 获取用户信息
     *
     * @param request  请求
     * @param response 响应
     * @param token    token
     * @return 返回
     */
    @PassToken
    @RequestMapping("api/getUserByToken")
    @ResponseBody
    public String getUserByToken(HttpServletRequest request, HttpServletResponse response, String token) {
        log.info(token);
        // token 认证
        if (token == null) {
            // throw new RuntimeException("无token，请重新登录");
            // throw new LoginException("001", "未登录"); // 抛出异常
            return ResMessage.error("001002", "token为空");
        }
        // 获取 token 中的 userNo
        SoUser user = new SoUser();
        try {
            // 从 token 中读取 userNo
            user.setUserNo(JWT.decode(token).getAudience().get(0));
        } catch (JWTDecodeException | IllegalArgumentException j) {
            // throw new RuntimeException("401");
            // j.printStackTrace();
            return ResMessage.error("001004", "token解析失败，请重新登录");
        }
        // 根据 userNo 从数据库中查询用户
        SoUser userFind = soUserService.findByUserInfo(user);
        if (userFind == null) {
            // throw new RuntimeException("用户不存在，请重新登录");
            return ResMessage.error("001005", "用户信息不存在，请重新登录");
        }
        // 使用 password 验证 token
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(userFind.getPassword())).build();
        try {
            jwtVerifier.verify(token);
        } catch (JWTVerificationException e) {
            // throw new RuntimeException("401");
            return ResMessage.error("001006", "签名验证不通过，请重新登录");
        }
        // 成功信息返回
        userFind.setPassword("");
        userFind.setToken(token);

        return ResMessage.success(userFind);
    }

    /**
     * token 失效后，获取新的token
     *
     * @param token 旧的token
     * @return 返回
     */
    @PassToken
    @RequestMapping("api/newToken")
    @ResponseBody
    public String getNewToken(HttpServletResponse response, String token) {
        // token 认证
        // 获取 token 中的 userNo
        SoUser user = new SoUser();
        try {
            // 从 token 中读取 userNo
            user.setUserNo(JWT.decode(token).getAudience().get(0));
        } catch (JWTDecodeException | IllegalArgumentException j) {
            // throw new RuntimeException("401");
            // j.printStackTrace();
            return ResMessage.error("001004", "token解析失败，请重新登录");
        }
        // 根据 userNo 从数据库中查询用户
        SoUser userFind = soUserService.findByUserInfo(user);
        if (userFind.getToken().equals(token)) {
            // 设置新的 token
            String newToken = tokenService.newToken(userFind);
            userFind.setToken(newToken);
            if (!newToken.equals("")) {
                // token 更新到 user 表
                SoUser upUser = new SoUser();
                upUser.setToken(newToken);
                upUser.setUserNo(userFind.getUserNo());
                soUserService.updateOneUser(upUser);
            }
        }
        log.info(ResMessage.success(userFind));
        // 设置 cookie
        writeCookie(response, "token", userFind.getToken(), 3600);
        return ResMessage.success(userFind);
    }
}
